//
//  面试.h
//  xiaorizi
//
//  Created by kun on 15/10/30.
//  Copyright © 2015年 origin. All rights reserved.
//

//
//  CNC面试.m
//  CarEnjoyClub
//
//  Created by qianfeng on 15/8/21.
//  Copyright (c) 2015年 CFM. All rights reserved.
//

#import <Foundation/Foundation.h>
/*
 2015年08月21日09:41:34
 
 1、assign retain copy strong  weak，的用法，区别
 
 
 
 （*）weak 和assign的区别
 The main difference between weak and assign is that the with weak, once the object being pointed to is no longer valid, the pointer is nilled out. Assigning the pointer the value nil avoids many crashes as messages sent to nil are essentially no-ops”
 Excerpt From: Daniel H Steinberg. “Developing iOS 7 Apps for iPad and iPhone.” Dim Sum Thinking, Inc, 2014. iBooks. iTunes - Books
 
 （*）深拷贝与浅拷贝
 
 http://blog.csdn.net/feitianxuxue/article/details/9275979
 用一句简单的话来说就是浅拷贝，只是对指针的拷贝，拷贝后两个指针指向同一个内存空间，深拷贝不但对指针进行拷贝，而且对指针指向的内容进行拷贝，经深拷贝后的指针是指向两个不同地址的指针。
  
     浅拷贝会出现什么问题呢？
 假如有一个成员变量的指针，char *m_data;
 其一，浅拷贝只是拷贝了指针，使得两个指针指向同一个地址，这样在对象块结束，调用函数析构的时，会造成同一份资源析构2次，即delete同一块内存2次，造成程序崩溃。
 其二，浅拷贝使得obj.m_data和obj1.m_data指向同一块内存，任何一方的变动都会影响到另一方。
 其三，在释放内存的时候，会造成obj1.m_data原有的内存没有被释放（这句话，刚开始我不太理解，如果没有走自定义的拷贝构造函数，申请内存空间，A obj1(obj);也不走默认构造函数，走的是默认的拷贝构造函数，何来分配空间直说，更不会造成obj1.m_data原有的内存没有被释放，这里刚开始我一直有疑问），造成内存泄露。
 事实是这样的，当delete obj.m_data, obj.m_data内存被释放后，由于之前obj.m_data和obj1.m_data指向的是同一个内存空间，obj1.m_data所指的空间不能在被利用了，delete obj1.m_data也不会成功，一致已经无法操作该空间，所以导致内存泄露。
 
     深拷贝采用了在堆内存中申请新的空间来存储数据，这样每个可以避免指针悬挂。
 
     下面来看看类string的拷贝构造函数
 
 http://www.cocoachina.com/ios/20141113/10213.html
 
 浅拷贝
 
 浅拷贝就是对内存地址的复制，让目标对象指针和源对象指向同一片内存空间。如：
 
 char* str = (char*)malloc(100);
 char* str2 = str;
 浅拷贝只是对对象的简单拷贝，让几个对象共用一片内存，当内存销毁的时候，指向这片内存的几个指针需要重新定义才可以使用，要不然会成为野指针。
 
 iOS 里面的浅拷贝：
 
 在 iOS 里面， 使用retain 关键字进行引用计数，就是一种更加保险的浅拷贝。他既让几个指针共用同一片内存空间，又可以在release 由于计数的存在，不会轻易的销毁内存，达到更加简单使用的目的。
 
 深拷贝：
 
 深拷贝是指拷贝对象的具体内容，而内存地址是自主分配的，拷贝结束之后，两个对象虽然存的值是相同的，但是内存地址不一样，两个对象也互不影响，互不干涉。
 
 copy 与 retain 的区别：
 
 copy 是创建一个新对象，retain 是创建一个指针，引用对象计数加一。 copy属性标识两个对象内容相同，新的对象retain count为1, 与旧有对象引用计数无关，旧有对象没有变化。copy减少对象对上下文的依赖。
 
 iOS里的深拷贝：
 
 iOS提供了copy和mutableCopy方法，顾名思义，copy就是复制了一个imutable的对象，而mutableCopy就是复制了一个mutable的对象。以下将举几个例子来说明。
 这里指的是NSString, NSNumber等等一类的对象。
 
 NSString *string = @”dddd";
 NSString *stringCopy = [string copy];
 NSMutableString *stringDCopy = [string mutableCopy];
 [stringMCopy appendString:@"!!"];
 查看内存可以发现，string和stringCopy指向的是同一块内存区域(weak reference),引用计数没有发生改变。而stringMCopy则是我们所说的真正意义上的复制，系统为其分配了新内存，是两个独立的字符串内容是一样的。
 
 拷贝构造：
 
 当然在 ios 中并不是所有的对象都支持copy，mutableCopy，遵守NSCopying协议的类可以发送copy消息，遵守NSMutableCopying协议的类才可以发送mutableCopy消息。
 
 假如发送了一个没有遵守上诉两协议而发送copy或者 mutableCopy,那么就会发生异常。但是默认的ios类并没有遵守这两个协议。如果想自定义一下copy 那么就必须遵守NSCopying,并且实现 copyWithZone: 方法，如果想自定义一下mutableCopy 那么就必须遵守NSMutableCopying,并且实现 mutableCopyWithZone: 方法。
 
 如果是我们定义的对象，那么我们自己要实现NSCopying , NSMutableCopying这样就能调用copy和mutablecopy了。举个例子：
 
 @interface MyObj : NSObject<NSCopying, NSMutableCopying>{
 NSMutableString *_name;
 NSString * _imutableStr ;
 int _age;
 }
 @property (nonatomic, retain) NSMutableString *name;
 @property (nonatomic, retain) NSString *imutableStr;
 @property (nonatomic) int age;
 copy拷贝构造：
 
 - (id)copyWithZone:(NSZone *)zone{
 MyObj *copy = [[[self class] allocWithZone :zone] init];
 copy->name = [_name copy];
 copy->imutableStr = [_imutableStr copy];
 copy->age = age;
 return copy;
 }
 mutableCopy拷贝构造：
 
 - (id)mutableCopyWithZone:(NSZone *)zone{
 MyObj *copy = NSCopyObject(self, 0, zone);
 copy->name = [_name mutableCopy];
 copy->age = age;
 return copy;
 }
 
 （*）代理  assign  为什么？ 不使引用计数器加一，避免循环引用。何为循环引用？
 （*）block 要使用copy 为什么？
 
 
 
 */

/*
 iOS路径沙盒文件管理，有需要的朋友可以参考下。
 
 
 一、iOS中的沙盒机制
 iOS应用程序只能对自己创建的文件系统读取文件，这个独立、封闭、安全的空间，叫做沙盒。它一般存放着程序包文件（可执行文件）、图片、音频、视频、plist文件、sqlite数据库以及其他文件。
 
 每个应用程序都有自己的独立的存储空间（沙盒）
 
 一般来说应用程序之间是不可以互相访问
 
 模拟器沙盒的位置
 
 /User/userName/Library/Application Support/iPhone Simulator
 
 当我们创建应用程序时，在每个沙盒中含有三个文件，分别是Document、Library和temp。
 
 Document：一般需要持久的数据都放在此目录中，可以在当中添加子文件夹，iTunes备份和恢复的时候，会包括此目录。
 
 Library：设置程序的默认设置和其他状态信息
 
 temp：创建临时文件的目录，当iOS设备重启时，文件会被自动清除
 
 获取沙盒目录
 
 获取程序的根目录（home）目录
 
 NSString *homePath = NSHomeDirectory()
 获取Document目录
 
 NSArray  *paths = NSSearchPathDorDirectoriesInDomains(NSDocumentDicrectory,, NSUserDomainMark, YES);
 
 NSString *docPath = [paths lastObject];
 获取Library目录
 
 NSArray *paths = NSSearchPathForDirectoriseInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
 NSString *docPath = [paths lastObject];
 获取Library中的Cache
 
 NSArray *paths = NSSearchPathForDirectoriseInDomains(NSCachesDirectory, NSUserDomainMask, YES);
 NSString *docPath = [paths lastObject];
 获取temp路径
 
 NSString *temp = NSTemporaryDirectory( );
 二、NSString类路径的处理方法
 
 文件路径的处理
 
 NSString *path=@"/Uesrs/apple/testfile.txt"
 
 常用方法如下
 
 获得组成此路径的各个组成部分，结果：（"/","User","apple","testfile.txt"）
 - (NSArray *)pathComponents;
 提取路径的最后一个组成部分，结果：testfile.txt
 
 - (NSString *)lastPathComponent;
 删除路径的最后一个组成部分，结果：/Users/apple
 - (NSString *)stringByDeletingLastPathCpmponent;
 将path添加到先邮路径的末尾，结果：/Users/apple/testfile.txt/app.txt
 
 - (NSString *)stringByAppendingPathConmponent:(NSString *)str;
 去路径最后部分的扩展名，结果：text
 
 - (NSString *)pathExtension;
 删除路径最后部分的扩展名，结果：/Users/apple/testfile
 
 - (NSString *)stringByDeletingPathExtension;
 路径最后部分追加扩展名，结果：/User/apple/testfile.txt.jpg
 
 - (NSString *)stringByAppendingPathExtension:(NSString *)str;
 
 
 三、NSData
 
 NSData是用来包装数据的
 
 NSData存储的是二进制数据，屏蔽了数据之间的差异，文本、音频、图像等数据都可用NSData来存储
 NSData的用法
 
 1.NSString与NSData互相转换
 
 NSData－> NSString
 NSString *aString = [[NSString alloc] initWithData:adataencoding:NSUTF8StringEncoding];
 NSString－>NSData
 NSString *aString = @"1234abcd";
 NSData *aData = [aString dataUsingEncoding: NSUTF8StringEncoding];
 将data类型的数据,转成UTF8的数据
 +(NSString *)dataToUTF8String:(NSData *)data
 {
 NSString *buf = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
 return [buf autorelease];
 }
 将string转换为指定编码
 +(NSString *)changeDataToEncodinString:(NSData *)data encodin:(NSStringEncoding )encodin{
 NSString *buf = [[[NSString alloc] initWithData:data encoding:encodin] autorelease];
 return buf;
 }
 2. NSData 与 UIImage
 NSData－>UIImage
 UIImage *aimage = [UIImage imageWithData: imageData];
 
 //例：从本地文件沙盒中取图片并转换为NSData
 NSString *path = [[NSBundle mainBundle] bundlePath];
 NSString *name = [NSString stringWithFormat:@"ceshi.png"];
 NSString *finalPath = [path stringByAppendingPathComponent:name];
 NSData *imageData = [NSData dataWithContentsOfFile: finalPath];
 UIImage *aimage = [UIImage imageWithData: imageData];
 3.NSData与NSArray NSDictionary
 
 +(NSString *)getLocalFilePath:(NSString *) fileName
 {
 return [NSString stringWithFormat:@"%@/%@%@", NSHomeDirectory(),@“Documents”,fileName];
 }
 包括将NSData写进Documents目录
 从Documents目录读取数据
 在进行网络数据通信的时候，经常会遇到NSData类型的数据。在该数据是dictionary结构的情况下，系统没有提供现成的转换成NSDictionary的方法，为此可以通过Category对NSDictionary进行扩展，以支持从NSData到NSDictionary的转换。声明和实现如下：
 + (NSDictionary *)dictionaryWithContentsOfData:(NSData *)data {
 CFPropertyListRef list = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, (CFDataRef)data, kCFPropertyListImmutable, NULL);
 if(list == nil) return nil;
 if ([(id)list isKindOfClass:[NSDictionary class]]) {
 return [(NSDictionary *)list autorelease];
 }
 else {
 CFRelease(list);
 return nil;
 }
 }
 四、文件管理常用方法
 
 NSFileManager
 
 创建一个文件并写入数据
 - (BOOL)createFileAtPath:(NSString *)path contents:(NSData *)data attributes:(NSDictionary *)attr;
 从一个文件中读取数据
 - (NSData *)contentsAtPath:(NSString *)path;
 scrPath路径上的文件移动到dstPath路径上，注意这里的路径是文件路径而不是目录
 - (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **) error;
 scrPath路径上的文件复制到dstPath路径上
 - (BOOL)copyItemAtPath:(NSString *)scrPath toPath:(NSString *)dstPath error:(NSError **) error;
 比较两个文件的内容是否一样
 - (BOOL)contentsEqualAtPath:(NSString *)path1 andPath:(NSString *)path2;
 文件是否存在
 - (BOOL)fileExistsAtPath:(NSString *)path;
 移除文件
 
 - (BOOL)removeItemAtPath:(NSString *)path error:(NSError **) error;
 创建文件管理
 
 NSFileManager *fileManager = [NSFileManager defaultManager];
 NSString *path = [NSHomeDirectory( )  stringByAppendingPathComponent:@"holyBible.txt"];
 将字符串转成NSData类型
 
 NSString *text = @"abcdefg";
 NSData *data = [text dataUsingEncoding: NSUTF8StringEncoding];
 写入文件
 BOOL success = [fileManager createFileAtPath:path contents:data attributes:nil];
 创建文件夹
 NSString *filePath = [path stringByAppendingPathComponent:@"holyBible.txt"];
 NSString *contect = @"abcdefg";
 BOOL success = [fm createFileAtPath:filePath contents:[content dataUsingEncoding: NSUTF8StringEncoding] attributes:nil];
 NSFileManager-读取内容
 NSData *fileData = [fileManager contentsAtPath:filePath];
 NSString *content = [[NSString alloc] initWithData:fileData dataUsingEncoding: NSUTF8StringEncoding];
 NSData-读取内容
 NSString *filePath = [path stringByAppendingPathComponent:@"holyBible.txt"];
 NSData *data = [NSData dataWithContentOfFile:filePath];
 NSString-读取内容
 
 NSString *filePath = [path stringByAppendingPathComponent:@"holyBible.txt"];
 NSString *content = [[NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
 移动、复制文件
 
 移动文件（重命名）
 NSString *toPath = [NSHomeDirectory( ) stringByAppendingPathComponent:@"hellogod/New Testament.txt"];
 [fm createDirectoryAtPath:[toPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
 NSError *error;
 BOOL isSuccess = [fm moveItemAtPath:filePath toPath:toPath error:&error];
 复制文件（重命名）
 NSString *copyPath = [NSHomeDirectory( ) stringByAppendingPathComponent:@"备份/Old Testament.txt"];
 [fm createDirectoryAtPath:[toPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil];
 BOOL success = [fm copyItemAtPath:toPath toPath:toPath error:nil];
 删除文件、获取文件大小
 判断文件是否存在和删除文件
 if([fm fileExistsAtPath]) {
 if ([fm removeItemAtPath:copyPath]) {
 NSLog(@"remove success");
 }
 }
 获取文件大小
 NSFileManager *fileManager = [NSFileManager defaultManager];
 获得文件的属性字典
 NSDictionary *attrDic = [fileManager attributesOfItemAtpath:sourcePath error:nil];
 NSNumber *fileSize = [attrDic objectForKey:NSFileSize];
 获取目录文件信息
 NSFileManager *fileManager = [NSFileManager defaultManager];
 NSString *enuPath = [NSHomeDirectoty( ) stringByAppendingPathComponent:@"Test"];
 NSDictionaryEnumerator *dirEnum = [fileManager enumeratorAtPath:enuPath];
 NSString *path = nil;
 while ((path = [dirEnum nextObject]} != nil){
 NSLog(@"%@",path);
 }
 
 */